# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function
import json
import requests
from datetime import datetime
from flask import current_app
from config import BaseConfig
from backend import LOG
from backend.service_manager.model import ai_service_manager
from backend.alg_api.v2.model import (
    ai_request_log_manager,
    ai_request_manager,
    ai_template_manager,
    AIRequestStatus,
)
from backend.exceptions import AIServiceException, ModelException
from backend.statistics.signals import counter_sent


class AIRequest(object):
    def __init__(self, ai_service_id, ai_template_id, method="POST", is_async=False):
        try:
            self.ai_service_id = ai_service_id
            self.ai_service = ai_service_manager.select_first(id=self.ai_service_id)
            self.ai_template_id = ai_template_id
            self.ai_template = ai_template_manager.select_first(id=self.ai_template_id)
            self.wfw_path = self.ai_service.path
            self.wfw_type = self.ai_service.type
            self.is_async = is_async
            self.status = AIRequestStatus.in_progress.name
            self.ai_request = ai_request_manager.create(
                ai_template_id=self.ai_template.id,
                ai_service_id=self.ai_service_id,
                is_async=self.is_async,
                status=self.status,
            )
            self.ai_request_log = ai_request_log_manager.create(
                ai_service_id=self.ai_service_id,
                ai_request_id=self.ai_request.id,
                status=self.status,
            )
        except (ModelException, AIServiceException) as e:
            LOG.error("初始化AIRequest异常：%s" % e.message)
            raise e
        self.wfw_method = method
        self.wfw_data = dict()
        self.wfw_headers = {"Content-Type": "application/json"}
        self.wfw_response = dict()

    # AI服务请求超时的客户端处理
    def handle_timeout(self):
        pass

    TIMEOUT = BaseConfig.AI_SERVICE_REQUEST_TIMEOUT
    TIMEOUT_HANDLER = handle_timeout

    def set_wfw_data(self, **kwargs):
        required_params = self.ai_template.required_params
        if required_params:
            for k in required_params.split(","):
                self.wfw_data.update({k: kwargs.get(k, None)})
                if self.wfw_data[k] is None:
                    self.save_request_failed()
                    raise AIServiceException(
                        message="AI请求: %d AI服务: %d 缺少必要参数"
                        % (self.ai_request.id, self.ai_service_id)
                    )

    def call_wfw(self, **kwargs):
        """
        ai wfw request call
        """
        if "data" in kwargs:
            self.wfw_data = json.dumps(kwargs["data"])
        if "headers" in kwargs:
            self.wfw_headers = kwargs["headers"]
        ret = requests.request(
            self.wfw_method,
            self.wfw_path,
            data=json.dumps(self.wfw_data),
            headers=self.wfw_headers,
            timeout=self.TIMEOUT,
        )
        # AI服务请求计数信号触发
        counter_sent.send(
            current_app._get_current_object(),
            service=self.ai_service,
            counter="call_total",
        )
        if ret.status_code != 200:
            self.save_request_failed()
            raise AIServiceException(
                message="AI请求: %d AI服务: %d 调用服务出错"
                % (self.ai_request.id, self.ai_service_id)
            )
        self.wfw_response = ret.json()

    def validate_results(self):
        if self.wfw_response.pop("code", 1) != 0:
            self.save_request_failed()
            msg = self.wfw_response.pop("msg", "")
            raise AIServiceException(
                message="AI请求: %d AI服务: %d 调用返回值报错: %s"
                % (self.ai_request.id, self.ai_service_id, msg)
            )
        required_result = self.ai_template.required_result
        if required_result:
            for k in required_result.split(","):
                if k not in self.wfw_response:
                    self.save_request_failed()
                    raise AIServiceException(
                        message="AI请求: %d AI服务: %d 调用返回值缺失关键字: %s"
                        % (self.ai_request.id, self.ai_service_id, k)
                    )

    def save_result(self):
        kwargs = dict(
            result=self.wfw_response, status=self.status, end_time=datetime.now(),
        )

        ai_request_manager.update(self.ai_request, **kwargs)

    def save_log(self):
        kwargs = dict(status=self.status, end_time=datetime.now(),)
        ai_request_log_manager.update(self.ai_request_log, **kwargs)

    def save_request_failed(self):
        self.status = AIRequestStatus.failed.name
        self.save_result()
        self.save_log()
        # AI服务请求成功计数触发
        counter_sent.send(
            current_app._get_current_object(),
            service=self.ai_service,
            counter="call_failed",
        )

    def save_request_done(self):
        self.status = AIRequestStatus.done.name
        self.save_result()
        self.save_log()
        # AI服务请求失败计数触发
        counter_sent.send(
            current_app._get_current_object(),
            service=self.ai_service,
            counter="call_done",
        )
